package com.icesoft.system.safe.helper;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.icesoft.framework.core.config.Cons;
import com.icesoft.framework.core.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public abstract class RequestHelper {

	private static final String XMLHttpRequest = "XMLHttpRequest";

	public static HttpServletRequest getRequest() {
		ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		if (attrs == null) {
			throw new BusinessException("无法找到请求体，请不要在多线程中使用");
		}
		return attrs.getRequest();
	}

	public static String getRequestUrl(HttpServletRequest request) {
		return replaceContextPath(request.getRequestURI(), request.getContextPath());
	}

	public static String getContextPathPre(HttpServletRequest request) {
		String contextPath = request.getContextPath();
		if (isEmptyPath(contextPath)) {
			return contextPath;
		}
		return contextPath + "/";
	}

	public static String replaceContextPath(String url, String contextPath) {
		if (isEmptyPath(contextPath)) {
			return url;
		}
		return url.replaceFirst(contextPath, "");

	}

	private static boolean isEmptyPath(String contextPath) {
		return "/".equals(contextPath);
	}

	public static HttpServletRequest getRequestOrNull() {
		ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		if (attrs == null) {
			return null;
		}
		return attrs.getRequest();
	}

	public static String getString(HttpServletRequest request, String name) {
		String value = request.getParameter(name);
		if (value == null) {
			@SuppressWarnings("unchecked")
			Map<String, String> paramMap = (Map<String, String>) request
					.getAttribute(Cons.REQUEST_RESOLVER_PARAM_MAP_NAME);
			if (paramMap != null) {
				value = paramMap.get(name);
			}
		}
		return value;
	}

	public static Boolean getBoolean(HttpServletRequest request, String name) {
		String param = getString(request, name);
		return param == null ? null : Boolean.parseBoolean(param);
	}

	public static Integer getInteger(HttpServletRequest request, String name) {
		String param = getString(request, name);
		return param == null ? null : Integer.parseInt(param);
	}

	public static Long getLong(HttpServletRequest request, String name) {
		String param = getString(request, name);
		return param == null ? null : Long.parseLong(param);
	}

	/**
	 * split ,
	 */
	public static String[] getStringArray(HttpServletRequest request, String name) {
		return getStringArray(request, name, ",");
	}

	public static String[] getStringArray(HttpServletRequest request, String name, String split) {
		String[] values = request.getParameterValues(name);
		if (values == null || (values.length == 1 && values[0].contains(split))) {
			String param = getString(request, name);
			return param == null ? null : StringUtils.split(param, split);
		}
		if (values.length == 1 && StringUtils.isEmpty(values[0])) {
			return new String[0];
		}
		return values;
	}

	public static int[] getIntArray(HttpServletRequest request, String name, String split) {
		String[] arrStrs = getStringArray(request, name, split);
		if (arrStrs == null) {
			return new int[0];
		}
		int[] arrs = new int[arrStrs.length];
		for (int i = 0; i < arrs.length; i++) {
			arrs[i] = Integer.parseInt(arrStrs[i]);

		}
		return arrs;
	}

	public static Map<String, String> getRequestParamMap(HttpServletRequest request) {
		Map<String, String> paramMap = new HashMap<>();
		Enumeration<?> pars = request.getParameterNames();
		while (pars.hasMoreElements()) {
			String par = (String) pars.nextElement();
			String[] values = request.getParameterValues(par);
			if (values.length == 1) {
				paramMap.put(par, values[0]);
			} else {
				StringBuilder vals = new StringBuilder();
				for (String v : values) {
					vals.append(v).append(",");
				}
				if (vals.length() > 0) {
					vals = new StringBuilder(vals.substring(0, vals.length() - 1));
				}
				paramMap.put(par, vals.toString());
			}

		}
		return paramMap;
	}

	/**
	 * 获取登录用户的IP，可伪造的IP获取方式，但是可解决通过代理访问的问题
	 */
	public static String getRemoteIP(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Real-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			return request.getRemoteAddr();
		}
		// 多个路由时，取第一个非unknown的ip
		final String[] arr = ip.split(",");
		for (final String str : arr) {
			if (!"unknown".equalsIgnoreCase(str)) {
				ip = str;
				break;
			}
		}
		return ip;
	}

	@Deprecated
	public static String getRemortIP(HttpServletRequest request) {
		return getRemoteIP(request);
	}

	public static boolean isLocalhost(HttpServletRequest request) {
		String remoteIp = getRemoteIP(request);
		return isLocalhost(remoteIp);
	}

	public static boolean isLocalhost(String ipAddr) {
		return "0:0:0:0:0:0:0:1".equals(ipAddr) || "127.0.0.1".equals(ipAddr);
	}

	public static boolean isAjax(HttpServletRequest request) {
		String xmlHttpRequest = request.getHeader("x-requested-with");
		if (xmlHttpRequest == null && request.getRequestURI().endsWith(".html")) {
			return false;
		}
		return XMLHttpRequest.equals(xmlHttpRequest);
	}

	public static String readBody(HttpServletRequest request) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		int i;
		InputStream is;
		try {
			is = request.getInputStream();
			while ((i = is.read()) != -1) {
				baos.write(i);
			}
			String paramStr = baos.toString();
			baos.close();
			return paramStr;
		} catch (Exception e) {
			throw new BusinessException("流读取出错");
		}
	}

	public static String getRequestParamString(HttpServletRequest request) {
		Object param = request.getAttribute(Cons.REQUEST_RESOLVER_PARAM_MAP_NAME);
		if (param == null) {
			String contextType = request.getContentType();
			try {
				if (contextType != null && contextType.contains(MediaType.APPLICATION_JSON_VALUE)
						&& request.getInputStream().isReady()) {
					param = RequestHelper.readBody(request);
				} else {
					param = new ObjectMapper().writeValueAsString(request.getParameterMap());
				}
			} catch (Exception e) {
				throw new BusinessException("request流读取出错");
			}
		}
		return param.toString();
	}
}
